/*
 * CudaAesOperationsTest.cpp
 *
 *  Created on: Feb 27, 2010
 *      Author: Łukasz Spintzyk
 */


#include "CudaAESInvOperations.h"
#include "CudaAESOperations.h"
#include "CudaAESFast.h"
#include "cudaUtils.h"
#include "CUDAAESEncrypter.h"
#include "BigInteger.h"


#include "aesUtils.h"
#include "AesKeyTestVectors.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <string>


#include <cppunit/TestRunner.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/extensions/TestFactoryRegistry.h>

#include <openssl/aes.h>


class TestCudaRijndael: public CPPUNIT_NS::TestCase
{
CPPUNIT_TEST_SUITE(TestCudaRijndael);
		CPPUNIT_TEST(testLockedMemory);
		CPPUNIT_TEST(testAesRound);
		CPPUNIT_TEST(testAesBlocksEncryption);
		//CPPUNIT_TEST(testDVDSSLEncryptionTime);
		//CPPUNIT_TEST(testDVDCUDAEncryptionTime);
		CPPUNIT_TEST(testAesBlockDec);
		CPPUNIT_TEST(testAesBlockEncryption);
		CPPUNIT_TEST(aesEncryptOpensslTest);
		CPPUNIT_TEST(aesEncryptDecryptOpensslTest_192);
		CPPUNIT_TEST(aesEncryptDecryptOpensslTest_256);
		CPPUNIT_TEST(aesDecryptOpensslTest);
	CPPUNIT_TEST_SUITE_END();

public:
	void setUp(void)
	{
		d_blockSize = 4 * 8;
		d_roundKeySize = (NR[NB_8][NB_8] + 1) * 4 * BLOCK_SIZE(NB_8) / 4;
		data = new byte[16];
		d_block = new byte[d_blockSize];
		d_copyBlock = new byte[d_blockSize];
		d_roundKey = new byte[d_roundKeySize];

		//expandKey((byte*)c_key256, NB_4, d_roundKey, NB_4, 0);

		setTestBlock(d_block, 8, 4);
		//setTestBlock(d_roundKey,d_roundKeySize/4, 4, 152);
		memcpy(d_copyBlock, d_block, sizeof(byte) * d_blockSize);

		data[0] ='1';
		data[1] ='1';
		data[2] ='2';
		data[3] ='2';
		data[4] ='3';
		data[5] ='3';
		data[6] ='4';
		data[7] ='4';
		data[8] ='5';
		data[9] ='5';
		data[10] ='1';
		data[11] ='2';
		data[12] ='3';
		data[13] ='4';
		data[14] ='5';
		data[15] ='6';
		aesEncryptInit();
		aesDecryptInit();
		aesFastCipherInit();
	}
	void tearDown(void)
	{
		for (int i = 0; i < d_blockSize; ++i)
		{
			d_block[i] = d_copyBlock[i] = 0;
		}

		delete[] d_block;
		delete[] d_copyBlock;
		delete[] d_roundKey;
	}

	void testIVEncryption()
	{
		uint32_t size = 1024;
		byte* host_data = new byte[size];
		memset(host_data, 0, size);
		byte myKey[32] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51,
				9, 200, 234, 2,
				19, 203, 34, 12,
				9, 200, 234, 2,
				12, 243,37, 77,

		};
		std::string vect = "9999888877776666111199998888777766661111";
		BigInteger iv(vect.c_str(), 0);
		CUDAAESEncrypter encrypter(iv, myKey);

		encrypter.encrypt(host_data, size, 0);

	}

	void testLockedMemory()
	{
		uint32_t size = 1024;
		CudaMemoryManager cuMem;
		byte* lockedMemory = cuMem.malloc(size, true);
		byte* d_mem = cuMem.malloc(size);
		byte* out = cuMem.malloc(size);
		byte* temp = new byte[size];

		memset(temp, 0, size);


		//std::cout << "\n Locked memory :" << std::endl;
		lockedMemory[1] = 22;
		lockedMemory[0] = 11;
		//printBlock((byte*)lockedMemory , 16, 4);
		cuMem.copy(d_mem, lockedMemory, size);

		writeToLockedMemory(d_mem, out);

		//std::cout << "\n Locked memory after write:" << std::endl;
		//printBlock((byte*)lockedMemory , 16, 4);

		cuMem.copy(temp, out, size);
		//std::cout << "\n Out memory :" << std::endl;
		//printBlock((byte*)temp , 16, 4);
		CPPUNIT_ASSERT(temp[0] == lockedMemory[0]);

		delete[] temp;
	}

	void testDVDSSLEncryptionTime()
	{
		uint32_t size = 1024*1024*50;
		byte* plainText = new byte[size];
		byte* encryptedText = new byte[size];
		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));


		byte myKey[32] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51,
				9, 200, 234, 2,
				19, 203, 34, 12,
				9, 200, 234, 2,
				12, 243,37, 77,

		};

		AES_set_encrypt_key(myKey, 16*8, &key);

		FILE* fp = fopen("/home/lukasz/dyplom/code/Cuda_AES/test/dvd.avi", "r");
		FILE* fw = fopen("/home/lukasz/dyplom/code/Cuda_AES/test/edvd.avi", "w");


		if (!fp){
			std::cout << "file not found"<<std::endl;
			return;
		}

		clock_t startSSL = clock();
		int n =0;
		while(fread(plainText, 1, size, fp)==size)
		{

			for(size_t i =0; i < size-16; i+=16)
			AES_encrypt((byte*)plainText+i,(byte*)encryptedText+i, &key);
			int len = fwrite(encryptedText, 1, size, fw);
			assert(len == size);
			n+=size;

		}
		std::cout << std::endl << n << std::endl;
		clock_t endSSL = clock();

		std::cout << "\nOpenSSL encrypt time = " << std::dec << (endSSL - startSSL)/CLOCKS_PER_SEC<< std::endl;
		fclose(fp);
		fclose(fw);
		std::cout << "\n OpenSSl Text:" << std::endl;
		printBlock((byte*)encryptedText , 12, 4);


		delete[] plainText;
		delete[] encryptedText;
	}

	void testDVDCUDAEncryptionTime()
	{
		uint32_t size = 1024*1024*50;
		uint32_t h_size = 128*16;
		CudaMemoryManager cuMem;
		byte* p;
		byte* plainText = cuMem.malloc(size);
		byte* encryptedText = cuMem.malloc(size);

		uint32_t* rk = (uint32_t*) cuMem.malloc(15*32);
		byte* buffer = new byte[size];//cuMem.malloc(size, true);





		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));


		byte myKey[32] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51,
				9, 200, 234, 2,
				19, 203, 34, 12,
				9, 200, 234, 2,
				12, 243,37, 77,

		};

		AES_set_encrypt_key(myKey, 16*8, &key);
		cuMem.copy((byte*)rk, (byte*)key.rd_key, sizeof(key.rd_key));


		FILE* fp = fopen("/home/lukasz/dyplom/code/Cuda_AES/test/dvd.avi", "r");
		FILE* fw = fopen("/home/lukasz/dyplom/code/Cuda_AES/test/edvd.avi", "w");

		if (!fp){
			std::cout << "file not found"<<std::endl;
			return;
		}



		clock_t startSSL = clock();
		int n =0;
		while(fread(buffer, 1, size, fp)==size)
		{
			cuMem.copy(plainText, buffer, size);
			for(int i =0; i < size-16*128; i+=16*128)
				aesEncryptBlocks((byte*)plainText+i,(byte*) encryptedText +i,  rk, NB_4, NB_4, 128);
			n+=size;
			cuMem.copy(buffer, encryptedText, size);
			fwrite(buffer, 1,  size, fw);
			//std::cout << std::endl << n << std::endl;
		}
		std::cout << std::endl << n << std::endl;
		clock_t endSSL = clock();

		std::cout << "\nCuda encrypt time = " << std::dec << (endSSL - startSSL)/CLOCKS_PER_SEC << std::endl;
		fclose(fp);
		fclose(fw);

		cuMem.copy(buffer, encryptedText, 48);
		std::cout << "\n Cuda Text:" << std::endl;
		printBlock((byte*)buffer , 12, 4);





		//delete buffer;
		//delete[] plainText;
		//delete[] encryptedText;
	}

	void testAesRound(void)
	{


		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));

		byte myKey[32] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51,
				9, 200, 234, 2,
				19, 203, 34, 12,
				9, 200, 234, 2,
				12, 243,37, 77,

		};
		std::string text = "Ala ma kota kota kot ma ale Ala ma kota kota kot ma ale ";
		char* plainText = new char[100];
		byte* encryptedTextSSL = new byte[100];
		byte* encryptedTextCUDA = new byte[100];

		memcpy(plainText, text.c_str(), 2*16);
		memcpy(encryptedTextCUDA, plainText, 2*16);
		memcpy(encryptedTextSSL, plainText, 2*16);


		AES_set_encrypt_key(myKey, 16*8, &key);


		//std::cout << "\n Plain Text:" << std::endl;
		//printBlock((byte*)encryptedTextCUDA, 4, 4);

		//std::cout << "\n OpenSSL roundKey:" << std::endl;
		//printBlock((byte*)key.rd_key, 11*4, 4);

		clock_t startSSL = clock();
		//for(int i =0; i <200000; i++)
			AES_encrypt((byte*)plainText,(byte*)encryptedTextSSL, &key);
		clock_t endSSL = clock();
		//std::cout << "\nOpenSSL encrypt time = " << std::dec << (endSSL - startSSL) << std::endl;

		//std::cout << "\n OpenSSL encrypted text:" << std::endl;
		//printBlock((byte*)encryptedTextSSL, 4, 4);






		clock_t startCUDA = clock();
		aesEncryptBlock2((byte*)encryptedTextCUDA, key.rd_key, NB_4, NB_4);
		clock_t endCUDA = clock();
		//std::cout << "\nCUDA encrypt time = " << std::dec <<(endCUDA - startCUDA) << std::endl;


		//std::cout << "\n CUDA encrypted text:" << std::endl;
		//printBlock((byte*)encryptedTextCUDA, 4, 4);

		CPPUNIT_ASSERT(memcmp(encryptedTextCUDA, encryptedTextSSL, 16) == 0);

		delete[] plainText;
		delete[] encryptedTextCUDA;
		delete[] encryptedTextSSL;

	}


	void testAesBlocksEncryption(void)
	{

		CudaMemoryManager cuMem;
		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));

		byte myKey[32] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51,
				9, 200, 234, 2,
				19, 203, 34, 12,
				9, 200, 234, 2,
				12, 243,37, 77,

		};
		std::string text = "Ala ma kota kota kot ma ale Ala ma kota kota kot ma ale ";
		char* plainText = new char[100];
		byte* encryptedTextSSL = new byte[100];
		byte* buffer = new byte[100];
		byte* encryptedTextCUDA = cuMem.malloc(100, false);
		uint32_t* rk =(uint32_t*) cuMem.malloc(15*32, false);

		memcpy(plainText, text.c_str(), 2*16);
		//memcpy(encryptedTextCUDA, plainText, 2*16);
		memcpy(encryptedTextSSL, plainText, 2*16);
		cuMem.copy(encryptedTextCUDA, (byte*)plainText, 2*16);


		AES_set_encrypt_key(myKey, 16*8, &key);
		//memcpy((byte*)rk, (byte*)key.rd_key, sizeof(key.rd_key));
		cuMem.copy((byte*)rk, (byte*)key.rd_key, sizeof(key.rd_key));



		std::cout << "\n Plain Text:" << std::endl;
		printBlock((byte*)plainText, 8, 4);

		//std::cout << "\n OpenSSL roundKey:" << std::endl;
		//printBlock((byte*)key.rd_key, 11*4, 4);

		clock_t startSSL = clock();
		//for(int i =0; i <100000; i++)
		for(int i =0 ; i < 2*16; i+=16)
		{
			AES_encrypt((byte*)plainText+i,(byte*)encryptedTextSSL+i, &key);
		}
		clock_t endSSL = clock();
		//std::cout << "\nOpenSSL encrypt time = " << std::dec << (endSSL - startSSL) << std::endl;

		std::cout << "\n OpenSSL encrypted text:" << std::endl;
		printBlock((byte*)encryptedTextSSL, 8, 4);



		clock_t startCUDA = clock();

		aesEncryptBlocks((byte*)encryptedTextCUDA, (byte*)encryptedTextCUDA,  rk, NB_4, NB_4, 2);

		clock_t endCUDA = clock();
	//	std::cout << "\nCUDA encrypt time = " << std::dec <<(endCUDA - startCUDA) << std::endl;


		cuMem.copy(buffer, encryptedTextCUDA, 100);
		std::cout << "\n CUDA encrypted text:" << std::endl;
		printBlock((byte*)buffer, 8, 4);

		CPPUNIT_ASSERT(memcmp(buffer, encryptedTextSSL, 2*16) == 0);

		delete[] plainText;
		delete[] buffer;
		//delete[] encryptedTextCUDA;
		delete[] encryptedTextSSL;

	}





	void testAesBlockEncryption(void)
	{
		const unsigned int size = 4 * 4;
		int wb = size/4;
		byte* d_copy = new byte[16];
		byte* d_outCopy = new byte[16];

		//"1122334455123456"
		byte c_key[16] =
		{
				0x0f, 0x15 , 0x71 , 0xc9
				, 0x47 , 0xd9 , 0xe8 , 0x59
				, 0x0c , 0xb7 , 0xad , 0xd6
				, 0xaf , 0x7f , 0x67 , 0x98
		};
		byte expected[] =
		{
			0xea, 0xf2, 0xa8, 0x06, 0xa7, 0xef, 0x6d, 0xcc,
			0x4e, 0xe7, 0x1c, 0x90, 0xaa, 0x28, 0x74, 0x6c
		};

		byte* data2 = new byte[16];
		memcpy(data2, data, 16);



		//std::cout << "\nInput bits"<<std::endl;
		//printBlock((byte*)data, size/4,4);
		//std::cout << "\nKey bits"<<std::endl;
		//printBlock((byte*)c_key, size/4,4);

		AES_KEY eKey;
		AES_set_encrypt_key(c_key, 16*8, &eKey);

		expandKey((byte*)c_key, NB_4, d_roundKey, NB_4, 0);
		aesEncryptBlock((byte*)data, d_roundKey, NB_4, NB_4);

		/*
		std::cout << "\n Round key "<<std::endl;
		printBlock((byte*)d_roundKey, size/4, 4);

		std::cout << "\n Round Key 2 "<<std::endl;
		printBlock((byte*)eKey.rd_key, size/4, 4);
		*/



		//std::cout << "\n Encrypted data "<<std::endl;
		//printBlock((byte*)data, size/4, 4);

		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));

		AES_set_decrypt_key(c_key, 16*8, &key);

		invExpandedKey(d_roundKey, NB_4, NB_4);
		aesDecryptBlock(data, (byte*)key.rd_key, NB_4, NB_4);



		CPPUNIT_ASSERT(memcmp(data, data2, size) == 0);
		delete data2;

	}

	void testAesBlockEncDec(void)
		{
			const unsigned int size = 4 * 4;
			byte* d_copy = new byte[16];
			byte* d_outCopy = new byte[16];

			//"1122334455123456"
			byte c_key[16] =
			{
					0x0f, 0x15 , 0x71 , 0xc9
					, 0x47 , 0xd9 , 0xe8 , 0x59
					, 0x0c , 0xb7 , 0xad , 0xd6
					, 0xaf , 0x7f , 0x67 , 0x98
			};
			byte expected[] =
			{
				0xea, 0xf2, 0xa8, 0x06, 0xa7, 0xef, 0x6d, 0xcc,
				0x4e, 0xe7, 0x1c, 0x90, 0xaa, 0x28, 0x74, 0x6c
			};




			//std::cout << "\nInput bits"<<std::endl;
			//printBlock((byte*)data, size/4,4);
			//std::cout << "\nKey bits"<<std::endl;
			//printBlock((byte*)c_key, size/4,4);

			expandKey((byte*)c_key, NB_4, d_roundKey, NB_4, 0);

			//std::cout << "\nExpanded key"<<std::endl;
			//printBlock(d_roundKey, 11*4,4);

			invExpandedKey(d_roundKey, NB_4, NB_4);
			aesEncryptBlock((byte*)data, d_roundKey, NB_4, NB_4);



			CPPUNIT_ASSERT(memcmp(data, expected, size) == 0);

		}

	void testAesBlockDec(void)
		{
			const unsigned int size = 4 * 4;
			byte* d_copy = new byte[16];
			byte* d_outCopy = new byte[16];

			//"1122334455123456"
			byte c_key[16] =
			{
					0x0f, 0x15 , 0x71 , 0xc9
					, 0x47 , 0xd9 , 0xe8 , 0x59
					, 0x0c , 0xb7 , 0xad , 0xd6
					, 0xaf , 0x7f , 0x67 , 0x98
			};
			byte cipher[] =
			{
				0xea, 0xf2, 0xa8, 0x06, 0xa7, 0xef, 0x6d, 0xcc,
				0x4e, 0xe7, 0x1c, 0x90, 0xaa, 0x28, 0x74, 0x6c
			};

			byte plain[] =
			{
				0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34,
				0x35, 0x35, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36
			};


			AES_KEY key;
			memset(&key, 0, sizeof(AES_KEY));

			AES_set_decrypt_key(c_key, 16*8, &key);

			AES_decrypt((byte*)cipher,(byte*)d_block, &key);
			expandKey((byte*)c_key, NB_4, d_roundKey, NB_4, 0);
			invExpandedKey(d_roundKey, NB_4, NB_4);

			//std::cout << "\n OpenSSL roundKey: " << key.rounds << std::endl;
			//printBlock((byte*)key.rd_key, 11*4, 4);
			//std::cout << "\n CUDA expand roundKey:" << std::endl;
			//printBlock(d_roundKey, 11*4, 4);

			memcpy(d_copyBlock, cipher, 16);

			aesDecryptBlock(d_copyBlock, (byte*)key.rd_key, NB_4, NB_4);



			//std::cout << "\n OpenSSL decrypted text:" << std::endl;
			//printBlock((byte*)d_block, 4, 4);

			//std::cout << "\n CUDA decrypted text:" << std::endl;
			//printBlock((byte*)d_copyBlock, 4, 4);

			CPPUNIT_ASSERT(memcmp(d_block, d_copyBlock, size) == 0);

		}

	void aesEncryptOpensslTest()
	{
		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));

		byte myKey[16] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51
		};
		std::string text = "Ala ma kota kot ";
		char* plainText = new char[100];
		char* encryptedTextSSL = new char[100];
		char* encryptedTextCUDA = new char[100];
		memcpy(plainText, text.c_str(), 17);
		memcpy(encryptedTextCUDA, plainText, 17);

		AES_set_encrypt_key(myKey, 16*8, &key);

		AES_encrypt((byte*)plainText,(byte*)encryptedTextSSL, &key);

		//std::cout << "\n OpenSSL encrypted text:" << std::endl;
		//printBlock((byte*)encryptedTextSSL, 4, 4);


		expandKey((byte*)myKey, NB_4, d_roundKey, NB_4, 0);

		//std::cout << "\n OpenSSL roundKey:" << std::endl;
		//printBlock((byte*)key.rd_key, 10, 4);
		//std::cout << "\n CUDA roundKey:" << std::endl;
		//printBlock(d_roundKey, 10, 4);

		aesEncryptBlock((byte*)encryptedTextCUDA, (byte*)key.rd_key, NB_4, NB_4);

		//std::cout << "\n CUDA encrypted text:" << std::endl;
		//printBlock((byte*)encryptedTextCUDA, 4, 4);

		CPPUNIT_ASSERT(memcmp(encryptedTextCUDA, encryptedTextSSL, 16) == 0);

		delete[] plainText;
		delete[] encryptedTextCUDA;
		delete[] encryptedTextSSL;
	}

	void aesEncryptDecryptOpensslTest_192()
		{
			AES_KEY key;
			memset(&key, 0, sizeof(AES_KEY));

			byte myKey[24] = {
					123, 23, 45, 66,
					21, 10, 05, 87,
					33, 62, 92, 11,
					0, 1, 78, 51,
					9, 200, 234, 2,
					19, 203, 34, 12,

			};
			std::string text = "Ala ma kota kota kot ma ale ";
			char* plainText = new char[100];
			char* encryptedTextSSL = new char[100];
			char* encryptedTextCUDA = new char[100];

			memcpy(plainText, text.c_str(), 17);
			memcpy(encryptedTextCUDA, plainText, 17);

			AES_set_encrypt_key(myKey, 24*8, &key);

			AES_encrypt((byte*)plainText,(byte*)encryptedTextSSL, &key);

			//std::cout << "\n OpenSSL encrypted text:" << std::endl;
			//printBlock((byte*)encryptedTextSSL, 6, 4);


			expandKey((byte*)myKey, NB_6, d_roundKey, NB_6, 0);

			//std::cout << "\n OpenSSL roundKey:" << std::endl;
			//printBlock((byte*)key.rd_key, 13*4, 4);
			//std::cout << "\n CUDA roundKey:" << std::endl;
			//printBlock(d_roundKey, 13*4, 4);

			aesEncryptBlock((byte*)encryptedTextCUDA, d_roundKey, NB_4, NB_6);

			//std::cout << "\n CUDA encrypted text:" << std::endl;
			//printBlock((byte*)encryptedTextCUDA, 6, 4);

			CPPUNIT_ASSERT(memcmp(encryptedTextCUDA, encryptedTextSSL, 16) == 0);

			delete[] plainText;
			delete[] encryptedTextCUDA;
			delete[] encryptedTextSSL;
		}


	void aesEncryptDecryptOpensslTest_256()
		{
			AES_KEY key, key2;
			memset(&key, 0, sizeof(AES_KEY));

			byte myKey[32] = {
					123, 23, 45, 66,
					21, 10, 05, 87,
					33, 62, 92, 11,
					0, 1, 78, 51,
					9, 200, 234, 2,
					19, 203, 34, 12,
					9, 200, 234, 2,
					12, 243,37, 77,

			};
			std::string text = "Ala ma kota kota kot ma ale ";
			char* plainText = new char[100];
			char* encryptedTextSSL = new char[100];
			char* encryptedTextCUDA = new char[100];

			memcpy(plainText, text.c_str(), 17);
			memcpy(encryptedTextCUDA, plainText, 17);
			memcpy(encryptedTextSSL, plainText, 17);

			//std::cout << "\n Plain Text:" << std::endl;
			//printBlock((byte*)encryptedTextCUDA, 4, 4);

			AES_set_encrypt_key(myKey, 16*8, &key);
			AES_set_encrypt_key(myKey, 16*8, &key2);

			//memset(d_roundKey, 0, 10);

			clock_t startSSL = clock();
			//for(int i =0; i <1000; i++)
				AES_encrypt((byte*)plainText,(byte*)encryptedTextSSL, &key);

			//addRoundKey((byte*)encryptedTextSSL, (byte*) key.rd_key, NB_4);
			//aesRound((byte*)encryptedTextSSL,(byte*) key.rd_key, NB_4);

			clock_t endSSL = clock();
			//std::cout << "\nOpenSSL encrypt time = " << (endSSL - startSSL) << std::endl;

			//std::cout << "\n OpenSSL encrypted text:" << std::endl;
			//printBlock((byte*)encryptedTextSSL, 4, 4);


			expandKey((byte*)myKey, NB_8, d_roundKey, NB_4, 0);

			//std::cout << "Round num = " <<std::dec<< (int) NR[NB_4][NB_4] << std::endl;
			//std::cout << "\n OpenSSL roundKey:" << std::endl;
			//printBlock((byte*)key.rd_key, 11*4, 4);
			//std::cout << "\n CUDA roundKey:" << std::endl;
			//printBlock(d_roundKey, 13*4, 4);

			clock_t startCUDA = clock();
			//for(int i =0; i < 100; ++i)
				aesEncryptBlock2((byte*)encryptedTextCUDA, key.rd_key, NB_4, NB_4);
				//aesEncryptBlock((byte*)encryptedTextCUDA, d_roundKey, NB_4, NB_8);

			clock_t endCUDA = clock();
			//std::cout << "\nCUDA encrypt time = " << (endCUDA - startCUDA) << std::endl;

			//std::cout << "\n CUDA encrypted text:" << std::endl;
			//printBlock((byte*)encryptedTextCUDA, 4, 4);

			CPPUNIT_ASSERT(memcmp(encryptedTextCUDA, encryptedTextSSL, 16) == 0);
			CPPUNIT_ASSERT(memcmp(key.rd_key, key2.rd_key, 11* 4 * sizeof(uint32_t)) == 0);

			delete[] plainText;
			delete[] encryptedTextCUDA;
			delete[] encryptedTextSSL;
		}


	void aesDecryptOpensslTest()
	{
		AES_KEY key;
		memset(&key, 0, sizeof(AES_KEY));

		byte myKey[16] = {
				123, 23, 45, 66,
				21, 10, 05, 87,
				33, 62, 92, 11,
				0, 1, 78, 51
		};
		std::string text = "Ala ma kota kot ";
		char* cipherText = new char[100];
		char* plainTextSSL = new char[100];
		char* plainTextCUDA = new char[100];
		memcpy(cipherText, text.c_str(), 17);
		memcpy(plainTextCUDA, cipherText, 17);

		AES_set_decrypt_key(myKey, 16*8, &key);

		AES_decrypt((byte*)cipherText,(byte*)plainTextSSL, &key);

		//std::cout << "\n OpenSSL plain text:" << std::endl;
		//printBlock((byte*)plainTextSSL, 4, 4);


		expandKey((byte*)myKey, NB_4, d_roundKey, NB_4, 0);

		//std::cout << "\n OpenSSL roundKey:" << std::endl;
		//printBlock((byte*)key.rd_key, 10, 4);
		//std::cout << "\n CUDA roundKey:" << std::endl;
		//printBlock(d_roundKey, 11*4, 4);

		aesDecryptBlock((byte*)plainTextCUDA, (byte*)key.rd_key, NB_4, NB_4);

		//std::cout << "\n CUDA encrypted text:" << std::endl;
		//printBlock((byte*)plainTextCUDA, 4, 4);

		CPPUNIT_ASSERT(memcmp(plainTextCUDA, plainTextSSL, 16) == 0);

		delete[] cipherText;
		delete[] plainTextCUDA;
		delete[] plainTextSSL;
	}
protected:

private:

	void rijndaelTest(byte* state, byte* d_key, NB nb, NB nk)
	{
		unsigned int bw = BLOCK_SIZE(nb) / 4;

		addRoundKey(state, d_key, NB_4);
		for (int i = 1; i < NR[nk][nb]; ++i)
		{
			aesRound(state, d_key + 4 * i * bw, NB_4);
		}

		//final round
		byteSub(state, NB_4);
		shiftRow(state, NB_4);
		addRoundKey(state, d_key + 4 * bw * NR[nk][nb], NB_4);

	}

	void setTestBlock(byte* block, int w, int h, int seed = 1)
	{
		int k = seed;
		for (int i = 0; i < w; ++i)
		{
			for (int j = 0; j < h; ++j)
			{
				block[i * h + j] = k++;
			}
		}
	}

	void printBlock(byte* block, int w, int h)
	{
		for (int j = 0; j < h; ++j)
		{
			for (int i = 0; i < w; ++i)
			{
				std::cout << std::hex << std::setw(4) << (unsigned int) block[i
						* h + j] << " ";
			}
			std::cout << std::endl;
		}
	}
	byte* data;
	byte* d_block;
	byte* d_copyBlock;
	byte* d_roundKey;
	int d_blockSize;
	int d_roundKeySize;

};
CPPUNIT_TEST_SUITE_REGISTRATION(TestCudaRijndael);

int main(int ac, char **av)
{
	//--- Create the event manager and test controller
	CPPUNIT_NS::TestResult controller;
	//--- Add a listener that colllects test result
	CPPUNIT_NS::TestResultCollector result;
	controller.addListener(&result);
	//--- Add a listener that print dots as test run.
	CPPUNIT_NS::BriefTestProgressListener progress;
	controller.addListener(&progress);
	//--- Add the top suite to the test runner
	CPPUNIT_NS::TestRunner runner;
	runner.addTest(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest());
	runner.run(controller);

	return result.wasSuccessful() ? 0 : 1;
}
